package com.ncloud.aaaa.service.impl;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;

import com.alibaba.dubbo.config.annotation.Service;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.ncloud.aaaa.base.Constant;
import com.ncloud.aaaa.model.Role;
import com.ncloud.aaaa.model.User;
import com.ncloud.aaaa.service.TokenService;
import com.ncloud.aaaa.util.EncryptUtils;
import com.ncloud.auth.config.RedisItem;
import com.ncloud.auth.config.RedisKeys;
import com.ncloud.auth.service.LocalTokenService;
import com.ncloud.auth.service.TokenConfig;
import com.ncloud.auth.util.JWT;
import com.ncloud.common.exception.UserException;

import io.jsonwebtoken.Claims;

@Service
public class TokenServiceImpl implements TokenService {

    private static final Logger logger = LogManager.getLogger(TokenServiceImpl.class);
    @Autowired
    private UserServiceImpl userService;
    @Autowired
    private TokenConfig tokenConfig;
    @Autowired
    private LocalTokenService tokenService;
    @Autowired
    private RoleServiceImpl roleService;

    @Override
    public JSONObject getToken(JSONObject userObj){
    	User user = JSON.parseObject(userObj.toJSONString(),User.class);
        //判断传入参数是否齐全
        if(StringUtils.isBlank(user.getAccount()) || StringUtils.isBlank(user.getPwd())){
            throw new UserException("账号或者密码不能为空");
        }
        User checkUser = null;
        boolean firstLogin = false;
        //读取redis是否已经登陆
        boolean redisCheck = true;
        byte[] mb = null;
        try {
            mb = tokenService.get(new RedisItem(RedisKeys.REDIS_USER_LOGIN_PREFIX+user.getAccount()));
        } catch (Exception e) {
            redisCheck = false;
            mb = null;
        }
        if(redisCheck && mb !=null){
            checkUser = JSON.parseObject(new String(mb),User.class);
            //从redis里面校验登陆用户信息
            if(checkUser!=null && StringUtils.isNotBlank(checkUser.getAccount())){
                if(Constant.allow_login_err_times<=checkUser.getErrTimes())
                    throw new UserException("1003","输入密码错误超过"+Constant.allow_login_err_times+"次,账号被锁定，请联系管理员");
                //判断密码
                if(!checkUser.getPwd().equals(EncryptUtils.encryptSHA(user.getPwd()))){
                    //更新错误次数
                    User errAccount = userService.addErrTimes(redisCheck, checkUser);
                    if(Constant.allow_login_err_times<=errAccount.getErrTimes())
                        throw new UserException("1003","输入密码错误超过"+Constant.allow_login_err_times+"次,账号被锁定，请联系管理员");
                    throw new UserException("1002","密码不正确");
                }else{
                    if(checkUser.getErrTimes()>0){
                        userService.clearErrTimes(redisCheck, checkUser);
                        List<RedisItem> list = new ArrayList<RedisItem>();
                        list.add(new RedisItem(RedisKeys.REDIS_USER_LOGIN_PREFIX+checkUser.getAccount(), checkUser, RedisKeys.REDIS_USER_LOGIN_EXPIRE));
                        tokenService.set(list);
                    }
                }
            }else{
                throw new UserException("1001","账号不存在");
            }

        }else{
            //从数据库中获取用户信息进行校验
            checkUser = userService.getByAccount(user.getAccount());
            if(checkUser!=null && StringUtils.isNotBlank(checkUser.getAccount())){
                if(Constant.allow_login_err_times<=checkUser.getErrTimes())
                    throw new UserException("1003","输入密码错误超过"+Constant.allow_login_err_times+"次,账号被锁定，请联系管理员");
                //判断密码
                if(!checkUser.getPwd().equals(EncryptUtils.encryptSHA(user.getPwd()))){
                    //更新错误次数
                    User errAccount = userService.addErrTimes(redisCheck,checkUser);
                    if(Constant.allow_login_err_times<=errAccount.getErrTimes())
                        throw new UserException("1003","输入密码错误超过"+Constant.allow_login_err_times+"次,账号被锁定，请联系管理员");
                    throw new UserException("1002","密码不正确");
                }else{
                	
                    if(checkUser.getFirstLoginTime()==null){
                    	firstLogin = true;
                    }
                    checkUser = userService.updateUserLoginTime(checkUser);
                    if(checkUser.getErrTimes()>0){
                        userService.clearErrTimes(redisCheck,checkUser);
                    }
                    if(redisCheck){
                        List<RedisItem> list = new ArrayList<RedisItem>();
                        list.add(new RedisItem(RedisKeys.REDIS_USER_LOGIN_PREFIX+checkUser.getAccount(), checkUser, RedisKeys.REDIS_USER_LOGIN_EXPIRE));
                        tokenService.set(list);
                    }
                }
            }else{
                throw new UserException("1001","账号不存在");
            }
        }
        
        try {
            String token = "";
            String refresh_token = "";
            Random random = new Random();
            String roundId = System.currentTimeMillis()+""+random.nextInt(100);
            JSONObject obj = new JSONObject();
            String userID = checkUser.getId()+"";
            obj.put("userID", userID);
            obj.put("roundId", roundId);
            obj.put("account",checkUser.getAccount());
            JSONObject refresh = new JSONObject();
            refresh.put("userID", userID);
            refresh.put("roundId", roundId);
            refresh.put("account",checkUser.getAccount());
            List<Role> roleList = roleService.getRoleList(checkUser.getId());
            obj.put("roleList",roleList);
            obj.put("firstLogin", firstLogin);
            token = JWT.createJWT(userID, userID, tokenConfig.getTokenExpiredTime() * 1000, obj);
            refresh_token = JWT.createJWT(userID, userID, tokenConfig.getRefreshTokenExpiredTime() * 1000, refresh);
            List<RedisItem> list = new ArrayList<RedisItem>();
            list.add(new RedisItem(tokenConfig.getTokenName(userID,roundId), token, tokenConfig.getTokenExpiredTime()* 1000));
            list.add(new RedisItem(tokenConfig.getRefreshTokenName(userID,roundId), refresh_token, tokenConfig.getRefreshTokenExpiredTime()* 1000));
            list.add(new RedisItem(tokenConfig.getUserInfoName(userID,roundId), obj, tokenConfig.getRefreshTokenExpiredTime()* 1000));
            tokenService.set(list);
            JSONObject result = new JSONObject();
            result.put("success", true);
            result.put("token", token);
            result.put("refresh_token", refresh_token);
            return result;
        } catch (Exception e) {
            logger.error(e);
            throw new UserException("9999",e.toString());
        }
    }

    @Override
    public JSONObject refreshToken(JSONObject freshToken) {
    	if(!freshToken.containsKey("refreshToken")){
    		throw new UserException("1004", "缺少参数");
    	}
    	String refreshToken = freshToken.getString("refreshToken");
        JSONObject result = new JSONObject();
        result.put("code", "201");
        Claims claims = JWT.parseJWT(refreshToken);
        String userID = claims.get("userID", String.class);
        String roundId = claims.get("roundId", String.class);
        String refreshTokenRedis = "";
        byte [] r = tokenService.get(new RedisItem(tokenConfig.getRefreshTokenName(userID,roundId)));
        if (r != null) {
            refreshTokenRedis = new String(r);
        }
        if(refreshToken != null && !"".equals(refreshToken) && refreshTokenRedis != null && !"".equals(refreshTokenRedis)) {
            JSONObject obj = JSON.parseObject(new String(tokenService.get(new RedisItem(tokenConfig.getUserInfoName(userID,roundId)))));
            String token = JWT.createJWT(userID, userID, tokenConfig.getTokenExpiredTime() * 1000, obj);
            result.put("code", "200");
            result.put("token", token);
            List<RedisItem> list = new ArrayList<RedisItem>();
            list.add(new RedisItem(tokenConfig.getTokenName(userID,roundId), token, tokenConfig.getTokenExpiredTime()));
            tokenService.set(list);
            List<RedisItem> expire = new ArrayList<RedisItem>();
            expire.add(new RedisItem(tokenConfig.getUserInfoName(userID,roundId),tokenConfig.getRefreshTokenExpiredTime()));
            expire.add(new RedisItem(tokenConfig.getRefreshTokenName(userID,roundId),tokenConfig.getRefreshTokenExpiredTime()));
            tokenService.expire(expire);
        }
        return result;
    }

    @Override
    public JSONObject destoryToken(JSONObject userObj) {
    	if(!userObj.containsKey("token")){
    		throw new UserException("1004", "缺少参数");
    	}
    	String token = userObj.getString("token");
        Claims claims = JWT.parseJWT(token);
        String userID = claims.get("userID", String.class);
        String roundId = claims.get("roundId", String.class);
        String account = claims.get("account", String.class);
        JSONObject obj = new JSONObject();
        tokenService.delete(new String[]{tokenConfig.getRefreshTokenName(userID,roundId), tokenConfig.getUserInfoName(userID,roundId), 
        		tokenConfig.getTokenName(userID,roundId),RedisKeys.REDIS_USER_LOGIN_PREFIX + account});
        obj.put("code", "200");
        return obj;
    }

}
